package 二三年8月;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 三数之和
 * 给你一个整数数组 nums ，判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ，同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
 *
 * 你返回所有和为 0 且不重复的三元组。
 *
 * 注意：答案中不可以包含重复的三元组。
 *
 * 思路： 可以换算一下 ， num【i】+num【j】 = -nums【k】
 *  所以可以使用循环来解决， 外层 n-2 , 内层n-1， 最内层n-2
 *
 *  三重循环的优化：
 *   使用双指针，遍历第一个元素，剩余两个元素使用双指针遍历
 */
public class L_15 {

    /**
     * 自己写的，超限，但是思路一样，优化，使用指针判断去重
     * @param nums
     * @return
     */
    public List<List<Integer>> threeSum(int[] nums) {
        int i, j, k;
        int length = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        // 刚开始给数组排序，目的是更好去重
        Arrays.sort(nums);
        for (k = 0; k < length - 2; k++) {
            for (i = k + 1; i < length - 1; i++) {
                for (j = i + 1; j < length; j++) {
                    if (nums[i] + nums[j] + nums[k] == 0) {
                        List<Integer> tmp = new ArrayList<>();
                        tmp.add(nums[i]);
                        tmp.add(nums[j]);
                        tmp.add(nums[k]);
                        res.add(tmp);
                    }
                }
            }
        }
        res = res.stream().distinct().collect(Collectors.toList());
        return res;
    }

    /**
     * 标准版
     * 双指针加去重校验
     * @param nums
     * @return
     */
    public List<List<Integer>> threeSumBiaoZhun(int[] nums) {
        List<List<Integer>> res = new ArrayList();
        int len = nums.length;
        if(nums == null || len < 3) return res;
        Arrays.sort(nums);
        for (int i = 0; i < len ; i++) {
            if(nums[i] > 0 ) break;  // 最小值大于0，则三数之和肯定不等于0
            if(i>0 && nums[i] == nums[i-1]){  // 去重
                 continue;
            }
            int l = i + 1;
            int r = len -1;
            while (l<r){
                int sum = nums[l] + nums[r]+ nums[i];
                if(sum == 0){
                    res.add(Arrays.asList(nums[l],nums[r],nums[i]));
                    while (l<r && nums[l] == nums[l+1]) {
                        l++;
                    } // 去重
                    while (l<r && nums[r] == nums[r-1]) {
                        r--;
                    } // 去重
                    // 指针进位
                    l++;
                    r--;
                } else if(sum < 0){
                    l++;
                }else if(sum > 0){
                    r--;
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int [] nums = {3,0,-2,-1,1,2};
        L_15 test = new L_15();
        List<List<Integer>> res = test.threeSum(nums);
        System.out.println(res);
    }
}


